package com.spring.boot.standard.admin.controller;

import java.io.*;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;

import com.spring.boot.standard.admin.common.beans.ColumnClass;
import com.spring.boot.standard.admin.common.utils.NameUtils;
import com.spring.boot.standard.admin.common.utils.ZipCompressor;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.poi.ss.formula.functions.Na;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import com.spring.boot.standard.admin.common.beans.PageData;
import com.spring.boot.standard.admin.common.CommonController;
import com.spring.boot.standard.admin.common.beans.CommonResult;
import com.spring.boot.standard.admin.entity.Templates;
import com.spring.boot.standard.admin.service.TemplatesService;

/**
 * @author qinhao
 * @since Thu Sep 09 14:31:17 CST 2021
 */
@RestController
@RequestMapping("/templates")
@Api(value="代码模板接口",tags={"templates(代码模板)接口"})
public class TemplatesController extends CommonController {
	
    @Autowired
    TemplatesService templatesService;

	@Value("${web.user-data-path}")
	private String userDataPath;

	@ApiOperation(value = "获取分页数据" ,notes = "获取分页数据" )
	@ApiImplicitParams({
		@ApiImplicitParam(name = "key" ,value = "搜索关键字名称" , required = false, dataType = "String"),
		@ApiImplicitParam(name = "keywords" ,value = "搜索关键字内容" , required = false, dataType = "String")
	})
    @RequestMapping(value = "/pagedata", method = { RequestMethod.GET  })
    public PageData<Templates> pagedata(Pageable pageable,String key,String keywords){
        return convertPage(templatesService.findAll(pageable,new Object[]{key,keywords}));
    }

	@ApiOperation(value = "获取列表数据" ,notes = "获取列表数据" )
	@ApiImplicitParams({
			@ApiImplicitParam(name = "groupname" ,value = "分组名称" , required = false, dataType = "String")
	})
	@RequestMapping(value = "/listdata", method = { RequestMethod.GET  })
	public List<Templates> listdata(String groupname){
		return templatesService.findListSimple(groupname);
	}

	@ApiOperation(value = "获取单条数据对象" ,notes = "获取单条数据对象")
	@ApiImplicitParams({
		@ApiImplicitParam(paramType = "query",name = "templateid" ,value = "代码模板ID" , required = true, dataType = "String")
	})
	@RequestMapping(value = "/singledata" ,method = { RequestMethod.GET })
	public Templates singledata(String templateid){
		return templatesService.findById(templateid);
	}

	@ApiOperation(value = "删除代码模板", notes = "删除代码模板" )
		@ApiImplicitParams({ @ApiImplicitParam(name = "ids", value = "ID拼接的字符串", required = true, dataType = "String")
	})
	@RequestMapping(value = "/delete" ,method = { RequestMethod.DELETE})
	public CommonResult delete(String ids) {
		try {
			String[] id_array = ids.split(",");
			for(String templateid:id_array){
				templatesService.deleteById(templateid);
			}
			cr = new CommonResult(true,0,null,"删除成功");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return cr;
	}

	@ApiOperation(value = "保存代码模板", notes = "保存代码模板,id列为空则为新增,不为空则为修改")
	@ApiImplicitParams({
		@ApiImplicitParam(name = "Templates",value = "代码模板",required = false,dataType = "Templates")
	})
	@RequestMapping(value = "/save" ,method = { RequestMethod.POST })
	public CommonResult save(Templates templates) {
		try {
			templatesService.save(templates);
			cr = new CommonResult(true,0,null,"保存成功");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return   cr;
	}

	@ApiOperation(value = "导出数据", notes = "导出数据")
	@ApiImplicitParams({
		@ApiImplicitParam(name = "key" ,value = "搜索关键字名称" , required = false, dataType = "String"),
		@ApiImplicitParam(name = "keywords" ,value = "搜索关键字内容" , required = false, dataType = "String")
	})
	@RequestMapping(value = "/exports", method = { RequestMethod.GET  })
	public ResponseEntity<byte[]> exports( Pageable pageable,String key,String keywords) {
		ResponseEntity<byte[]> entity = null;
	    String[] titleNameArray = {"模板名称@模板名称","包名@例如manager","项目名@例如ma-mananger","相对路径@/manager-server-web/src/","生成的文件名@build.gradle","模板内容@freemarker","备注@备注"};
		String[] fieldNameArray = {"templatename","packagename","projectname","relativepath","newfilename","templatecontent","remark"};
		try {
			//根据条件获取数据
            List<Templates> data = templatesService.findAll(pageable,new Object[]{key,keywords}).getContent();
			//数据转换成流并导出
			InputStream is = super.exportExcelContent(data,titleNameArray,fieldNameArray);
			byte[] body = new byte[is.available()];
			is.read(body);
			HttpHeaders headers = new HttpHeaders();
			String exportFilename = new SimpleDateFormat("yyyyMMddhhmmssSSS").format(new Date()) + ".xls";
			headers.add("Content-Disposition", "attchement;filename=" + exportFilename);
			HttpStatus statusCode = HttpStatus.OK;
			entity = new ResponseEntity<byte[]>(body, headers, statusCode);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return entity;
	}

	@ApiOperation(value = "导入代码模板", notes = "导入代码模板")
    @RequestMapping(value = "/imports", method = { RequestMethod.POST })
	public CommonResult imports(@RequestParam("file") MultipartFile file) {
		int imp_num = 0;
		//如果文件不为空，写入上传路径
		try {
			if(!file.isEmpty()) {
				String[] fieldNameArray = {"templatename","packagename","projectname","relativepath","newfilename","templatecontent","remark"};
				List<Map<String,String>> list = super.getExcelContent(file, fieldNameArray);
                imp_num =  templatesService.saveFromList(list);
				cr = new CommonResult(true,0,null,"导入成功，导入数据："+imp_num+"条！");
			} else {
				cr = new CommonResult(false,500,null,"文件上传失败！");
			}
		} catch (Exception e) {
			cr = new CommonResult(false,500,null,super.getPointOfException(e.getMessage()));
		}
		return  cr;
	}

	@ApiOperation(value = "微应用骨架生成", notes = "微应用骨架生成" )
	@ApiImplicitParams({
			@ApiImplicitParam(name = "projectName" ,value = "项目名称" , required = true, dataType = "String"),
			@ApiImplicitParam(name = "corpName" ,value = "公司名称" , required = true, dataType = "String")
	})
	@RequestMapping(value = "/microserviceArcMa" ,method = { RequestMethod.POST})
	public CommonResult microserviceArcMa(String projectName,String corpName) {
		return makeArc(projectName,corpName,"microservice-arc-ma");
	}

	@ApiOperation(value = "微服务骨架生成", notes = "微服务骨架生成" )
	@ApiImplicitParams({
			@ApiImplicitParam(name = "projectName" ,value = "项目名称" , required = true, dataType = "String"),
			@ApiImplicitParam(name = "corpName" ,value = "公司名称" , required = true, dataType = "String")
	})
	@RequestMapping(value = "/microserviceArcMs" ,method = { RequestMethod.POST})
	public CommonResult microserviceArcMs(String projectName,String corpName) {
		return makeArc(projectName, corpName, "microservice-arc-ms");
	}

	@ApiOperation(value = "微应用代码生成", notes = "微应用代码生成" )
	@ApiImplicitParams({
			@ApiImplicitParam(name = "columnJson" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "modalName" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "modalIcon" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "modalCName" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "moduleTypes" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "functionTypes" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "author" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "projectName" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "typeName" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "dbName" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "corpName" ,value = "公司名称" , required = false, dataType = "String")
	})
	@RequestMapping(value = "/microserviceCodeMa" ,method = { RequestMethod.POST})
	public CommonResult microserviceCodeMa(String columnJson,String modalName,String modalIcon,String modalCName,
										   String moduleTypes,String functionTypes,String author,String projectName,String typeName,String dbName,String corpName) {
		return makeCode("microservice-ma",columnJson,modalName,modalIcon,modalCName,
				moduleTypes,functionTypes,author,projectName,typeName,dbName,corpName);
	}

	@ApiOperation(value = "微服务代码生成", notes = "微服务代码生成" )
	@ApiImplicitParams({
			@ApiImplicitParam(name = "columnJson" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "modalName" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "modalIcon" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "modalCName" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "moduleTypes" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "functionTypes" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "author" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "projectName" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "typeName" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "dbName" ,value = "项目名称" , required = false, dataType = "String"),
			@ApiImplicitParam(name = "corpName" ,value = "公司名称" , required = false, dataType = "String")
	})
	@RequestMapping(value = "/microserviceCodeMs" ,method = { RequestMethod.POST})
	public CommonResult microserviceCodeMs(String columnJson,String modalName,String modalIcon,String modalCName,
										   String moduleTypes,String functionTypes,String author,String projectName,String typeName,String dbName,String corpName) {
		return makeCode("microservice-ms",columnJson,modalName,modalIcon,modalCName,
				moduleTypes,functionTypes,author,projectName,typeName,dbName,corpName);
	}

	private CommonResult makeArc(String projectName,String corpname, String groupName){
		String uploadid = UUID.randomUUID().toString().replace("-","");
		try {
			//按文件生成代码
			if(projectName!=null && projectName.split("-").length>=2){

				//数据初始化
				String name = NameUtils.getName(projectName);
				Map<String,Object> dataMap = new HashMap<>();
				String codePath = userDataPath+"/codes/"+uploadid;//代码生成到这个目录下
				List<Templates> templatesList = templatesService.findList(groupName);

				//freemarker初始化
				Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
				cfg.setCacheStorage(new freemarker.cache.NullCacheStorage());

				for(Templates templates : templatesList){
					String relativepath = templates.getRelativepath();
					String newfilename = templates.getNewfilename();
					String templatecontent = templates.getTemplatecontent();
					relativepath = relativepath.replace("${name}",name).replace("${corpname}",corpname);

					//模板参数初始化
					dataMap.put("name",name);//例如：user
					dataMap.put("projectName",projectName);//例如：ma-user
					dataMap.put("corpname",corpname);//例如：sgcc

					//初始化自定义发布目录
					File userDataPathDir = new File(userDataPath);
					if(!userDataPathDir.exists()){
						userDataPathDir.mkdirs();
					}

					//初始化最终生成的文件目录
					String newFilePath = codePath + relativepath + newfilename;
					File newFile = new File(newFilePath);
					if(!newFile.getParentFile().exists()){
						newFile.getParentFile().mkdirs();
					}

					//初始化freemarker
					StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
					stringTemplateLoader.putTemplate("myTemplate", templatecontent);
					cfg.setTemplateLoader(stringTemplateLoader);
					Template template = cfg.getTemplate("myTemplate","utf-8");

					//生成代码文件
					FileOutputStream fos = new FileOutputStream(newFile);
					Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"),10240);
					try {
						template.process(dataMap,out);
					} catch (Exception e) {
						e.printStackTrace();
					} finally {
						out.close();
					}
				}

				//开始压缩
				String zipPath = userDataPath +"/zip/codes/"+uploadid+"/";
				File zipPathFile = new File(zipPath);
				if(!zipPathFile.exists()){
					zipPathFile.mkdirs();
				}
				zipPath += "code.zip";
				codePath += "/";
				ZipCompressor zc = new ZipCompressor(zipPath);
				zc.compress(codePath+name+"-server-api",codePath+name+"-server-dao",codePath+name+"-server-service",codePath+name+"-server-web",codePath+"settings.gradle",codePath+"gradle.properties",codePath+"pubdepload.gradle");
			}else{
				cr = new CommonResult(false, 500, null, "异常错误！");
			}
		} catch (Exception e) {
			e.printStackTrace();
			cr = new CommonResult(false, 500, null, e.getMessage());
		}
		cr = new CommonResult(true, 200, "zip/codes/"+uploadid+"/code.zip", null);
		return cr;
	}

	private CommonResult makeCode(String groupName,String columnJson,String modalName,String modalIcon,String modalCName,
								 String moduleTypes,String functionTypes,String author,String projectName,String typeName,String dbName,String corpname){
		String uploadid = UUID.randomUUID().toString().replace("-","");
		try {
			//按文件生成代码
			if(projectName!=null && projectName.split("-").length>=2){

				//数据初始化
				String name = NameUtils.getName(projectName);
				String databaseTFName = NameUtils.getTableDataTFName(dbName);
				Map<String,Object> dataMap = new HashMap<>();
				String codePath = userDataPath+"/codes/"+uploadid;//代码生成到这个目录下
				List<Templates> templatesList = templatesService.findList(groupName);

				//表模型字段内容数据转换 循环补充两个字段 Java类型
				List<Map<String,String>> javaColumnList = gson.fromJson(NameUtils.getJavaDataType(columnJson),List.class);
				List<ColumnClass> columnJavaClassList  = NameUtils.convertMapToClassOfList(javaColumnList);

				//表模型字段内容数据转换 循环补充两个字段 Xml类型
				List<Map<String,String>> xmlColumnList = gson.fromJson(NameUtils.getXmlDataType(columnJson),List.class);
				List<ColumnClass> columnXmlClassList  = NameUtils.convertMapToClassOfList(xmlColumnList);

				//按文件生成代码
				if(moduleTypes!=null && moduleTypes.length()>0) {
					String[] function_types = functionTypes.split(",");
					List<String> function_list = new ArrayList<String>();
					for (String function : function_types) {
						function_list.add(function);
					}

					//freemarker初始化
					Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
					cfg.setCacheStorage(new freemarker.cache.NullCacheStorage());

					for(Templates templates : templatesList){
						String templateid = templates.getTemplateid();

						//id在勾选的范围内的代码模板
						if(moduleTypes.contains(templateid)){

							String relativepath = templates.getRelativepath();
							String newfilename = templates.getNewfilename();
							newfilename = newfilename.replace("${name}",name).replace("${modalName}",NameUtils.replaceUnderLineAndUpperCase(modalName));
							String templatecontent = templates.getTemplatecontent();
							relativepath = relativepath.replace("${name}",name)
									.replace("${modalName}",NameUtils.replaceUnderLine(modalName))
									.replace("${dbName}",databaseTFName)
									.replace("${corpname}",corpname);
							String commonPackageName = "com."+corpname+"." + name;//通用包名
							String commonPackagePath = "/src/main/java/com/" + corpname + "/" + name;//通用包路径

							//模板参数初始化
							String className = NameUtils.replaceUnderLineAndUpperCase(modalName);
							String newFilePath = codePath + relativepath + newfilename;
							File newFile = new File(newFilePath);
							if(!newFile.getParentFile().exists()){
								newFile.getParentFile().mkdirs();
							}

							dataMap.put("modalCName",modalCName);//表名描述,例如：用户
							dataMap.put("className",className);//类名，例如：User
							dataMap.put("serverName",projectName);//ma-user ms-test2
							dataMap.put("modalName",NameUtils.replaceUnderLine(modalName));//表名，例如：user，userScore
							dataMap.put("dbTable",modalName);//表名，例如：user,user_score
							dataMap.put("dbName",databaseTFName);//数据库名称，例如zlink

							dataMap.put("model_column",columnJavaClassList);//表字段描述数组
							dataMap.put("model_xml_column",columnXmlClassList);//mapper文件中需要用的的表字段转换后数组
							dataMap.put("function_list",function_list);//类中的方法名数组，例如：[findPage,findList...]

							dataMap.put("packageNameBase",commonPackageName);//基础包名，例如："com.nesun.test2"

							dataMap.put("date",new Date().toString());//"date" -> "Mon Oct 18 14:55:37 CST 2021"
							dataMap.put("corpname",corpname);//"corpName" -> "nesun"
							dataMap.put("author",author);//例如：qinhao
							// 8a80cb817bc9fffb017bca7946fe000c是mapperXml模板的templateid
							dataMap.put("mapperXml",moduleTypes.contains("8a80cb817bc9fffb017bca7946fe000c")?"true":"false");//例如：true

							//初始化自定义发布目录
							File userDataPathDir = new File(userDataPath);
							if(!userDataPathDir.exists()){
								userDataPathDir.mkdirs();
							}

							//初始化freemarker
							StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
							stringTemplateLoader.putTemplate("myTemplate", templatecontent);
							cfg.setTemplateLoader(stringTemplateLoader);
							Template template = cfg.getTemplate("myTemplate","utf-8");

							//生成代码文件
							FileOutputStream fos = new FileOutputStream(newFile);
							Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"),10240);
							try {
								template.process(dataMap,out);
							} catch (Exception e) {
								e.printStackTrace();
							} finally {
								out.close();
							}
						}

					}

					//开始压缩
					String zipPath = userDataPath +"/zip/codes/"+uploadid+"/";
					File zipPathFile = new File(zipPath);
					if(!zipPathFile.exists()){
						zipPathFile.mkdirs();
					}
					zipPath += "code.zip";
					codePath += "/";
					ZipCompressor zc = new ZipCompressor(zipPath);
					zc.compress(codePath+name+"-server-api",codePath+name+"-server-dao",codePath+name+"-server-service",codePath+name+"-server-web");
				}

			}else{
				cr = new CommonResult(false, 500, null, "异常错误！");
			}
		} catch (Exception e) {
			e.printStackTrace();
			cr = new CommonResult(false, 500, null, e.getMessage());
		}
		cr = new CommonResult(true, 200, "zip/codes/"+uploadid+"/code.zip", null);
		return cr;
	}

}